package org.zkdemo.snmp;

import java.io.IOException;

import org.apache.log4j.Logger;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;

public class SnmpPinger implements Runnable
{
    private static final Logger LOGGER    = Logger.getLogger(SnmpPinger.class);
    
    private Snmp                snmp      = null;
    private String              address   = null;
    private TransportMapping    transport = null;
    
    public SnmpPinger(String address)
    {
        this.address = address;
    }
    
    @Override
    public void run()
    {
        try
        {
            transport = new DefaultUdpTransportMapping();
            snmp = new Snmp(transport);
            // Do not forget this line!
            transport.listen();
            
            String sysDescr = getAsString(new OID(".1.3.6.1.2.1.1.1.0"));
            String sysOid = getAsString(new OID(".1.3.6.1.2.1.1.2.0"));
            String sysLabel = getAsString(new OID(".1.3.6.1.2.1.1.5.0"));
            
            if (sysDescr != null && sysLabel != null && sysOid != null)
            {
                synchronized (LOGGER)
                {
                    LOGGER.info("----------------------------------------------------------------");
                    LOGGER.info(address);
                    LOGGER.info(sysDescr);
                    LOGGER.info(sysOid);
                    LOGGER.info(sysLabel);
                    LOGGER.info("----------------------------------------------------------------");
                }
            }
        }
        catch (Exception e)
        {
            LOGGER.error("Error", e);
        }
        finally
        {
            close();
        }
    }
    
    public String getAsString(OID oid) throws IOException
    {
        ResponseEvent event = get(new OID[] { oid });
        PDU pdu = event.getResponse();
        if (pdu == null)
        {
            return null;
        }
        
        return pdu.get(0).getVariable().toString();
    }
    
    public ResponseEvent get(OID oids[]) throws IOException
    {
        PDU pdu = new PDU();
        for (OID oid : oids)
        {
            pdu.add(new VariableBinding(oid));
        }
        pdu.setType(PDU.GET);
        ResponseEvent event = snmp.send(pdu, getTarget(), null);
        if (event != null)
        {
            return event;
        }
        
        throw new IOException("GET timed out");
    }
    
    protected void close()
    {
        if (snmp != null)
        {
            try
            {
                snmp.close();
            }
            catch (Exception e)
            {
                LOGGER.error("Error closing snmp.", e);
            }
        }
        
        if (transport != null)
        {
            try
            {
                transport.close();
            }
            catch (Exception e)
            {
                LOGGER.error("Error closing transport.", e);
            }
        }
    }
    
    protected Target getTarget()
    {
        Address targetAddress = GenericAddress.parse(address);
        CommunityTarget target = new CommunityTarget();
        target.setCommunity(new OctetString("public"));
        target.setAddress(targetAddress);
        target.setRetries(2);
        target.setTimeout(1500);
        target.setVersion(SnmpConstants.version2c);
        return target;
    }
}
